001 /* 002 * Copyright 2005 Stephen J. McConnell. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 013 * implied. 014 * 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 019 package net.dpml.library; 020 021 import java.io.File; 022 023 import net.dpml.lang.Version; 024 import net.dpml.lang.Enum; 025 026 import net.dpml.transit.Artifact; 027 028 /** 029 * Enumeration identifying resource features. 030 * 031 * @author <a href="http://www.dpml.net">Digital Product Meta Library</a> 032 * @version 1.1.0 033 */ 034 public final class Feature extends Enum 035 { 036 static final long serialVersionUID = 1L; 037 038 /** 039 * Resource name. 040 */ 041 public static final Feature NAME = new Feature( "name" ); 042 043 /** 044 * Resource group. 045 */ 046 public static final Feature GROUP = new Feature( "group" ); 047 048 /** 049 * Resource version. 050 */ 051 public static final Feature VERSION = new Feature( "version" ); 052 053 /** 054 * Resource decimal version. 055 */ 056 public static final Feature DECIMAL = new Feature( "decimal" ); 057 058 /** 059 * Resource version. 060 */ 061 public static final Feature URI = new Feature( "uri" ); 062 063 /** 064 * Resource spec. 065 */ 066 public static final Feature SPEC = new Feature( "spec" ); 067 068 /** 069 * Resource path. 070 */ 071 public static final Feature PATH = new Feature( "path" ); 072 073 /** 074 * Resource filename. 075 */ 076 public static final Feature FILENAME = new Feature( "filename" ); 077 078 /** 079 * Project basedir. 080 */ 081 public static final Feature BASEDIR = new Feature( "basedir" ); 082 083 /** 084 * Array of scope enumeration values. 085 */ 086 private static final Feature[] ENUM_VALUES = 087 new Feature[]{NAME, GROUP, VERSION, DECIMAL, URI, SPEC, PATH, FILENAME, BASEDIR}; 088 089 /** 090 * Returns an array of activation enum values. 091 * @return the activation policies array 092 */ 093 public static Feature[] values() 094 { 095 return ENUM_VALUES; 096 } 097 098 /** 099 * Internal constructor. 100 * @param label the enumeration label. 101 * @param index the enumeration index. 102 */ 103 private Feature( String label ) 104 { 105 super( label ); 106 } 107 108 /** 109 * Return a string representation of the scope. 110 * @return the string value 111 */ 112 public String toString() 113 { 114 return getName().toUpperCase(); 115 } 116 117 /** 118 * Return a feature. 119 * @param value the feature name 120 * @return the feature 121 * @exception IllegalArgumentException if the name if not a recognized feature. 122 */ 123 public static Feature parse( String value ) throws IllegalArgumentException 124 { 125 if( value.equalsIgnoreCase( "name" ) ) 126 { 127 return NAME; 128 } 129 else if( value.equalsIgnoreCase( "group" ) ) 130 { 131 return GROUP; 132 } 133 else if( value.equalsIgnoreCase( "version" ) ) 134 { 135 return VERSION; 136 } 137 else if( value.equalsIgnoreCase( "decimal" ) ) 138 { 139 return DECIMAL; 140 } 141 else if( value.equalsIgnoreCase( "uri" ) ) 142 { 143 return URI; 144 } 145 else if( value.equalsIgnoreCase( "spec" ) ) 146 { 147 return SPEC; 148 } 149 else if( value.equalsIgnoreCase( "path" ) ) 150 { 151 return PATH; 152 } 153 else if( value.equalsIgnoreCase( "filename" ) ) 154 { 155 return FILENAME; 156 } 157 else if( value.equalsIgnoreCase( "basedir" ) ) 158 { 159 return BASEDIR; 160 } 161 else 162 { 163 final String error = 164 "Unrecognized feature argument [" + value + "]"; 165 throw new IllegalArgumentException( error ); 166 } 167 } 168 169 /** 170 * Return the value of a feature. 171 * @param resource the target resource 172 * @param feature the feature 173 * @return the resolved value 174 */ 175 public static String resolve( Resource resource, Feature feature ) 176 { 177 return resolve( resource, feature, null, false ); 178 } 179 180 /** 181 * Return the value of a feature. 182 * @param resource the target resource 183 * @param feature the feature 184 * @param type the selected type 185 * @return the resolved value 186 */ 187 public static String resolve( Resource resource, Feature feature, Type type ) 188 { 189 return resolve( resource, feature, type, false ); 190 } 191 192 /** 193 * Return the value of a feature. 194 * @param resource the target resource 195 * @param feature the feature 196 * @param type the selected type 197 * @param alias flag indicated that alias based uri resolution is requested 198 * @return the resolved value 199 */ 200 public static String resolve( Resource resource, Feature feature, Type type, boolean alias ) 201 { 202 if( null != type && !resource.isa( type.getID() ) ) 203 { 204 final String error = 205 "The feature request for the type [" 206 + type 207 + "] from the resource [" 208 + resource 209 + "] cannot be fullfilled because the resource does not declare " 210 + "production of the requested type."; 211 throw new FeatureRuntimeException( error ); 212 } 213 214 if( feature.equals( Feature.NAME ) ) 215 { 216 return resource.getName(); 217 } 218 else if( feature.equals( Feature.GROUP ) ) 219 { 220 return resource.getParent().getResourcePath(); 221 } 222 else if( feature.equals( Feature.VERSION ) ) 223 { 224 String version = resource.getVersion(); 225 if( null == version ) 226 { 227 return ""; 228 } 229 else 230 { 231 return version; 232 } 233 } 234 else if( feature.equals( Feature.DECIMAL ) ) 235 { 236 Version version = resource.getDecimalVersion(); 237 if( null == version ) 238 { 239 return ""; 240 } 241 else 242 { 243 return version.toString(); 244 } 245 } 246 else if( feature.equals( Feature.URI ) ) 247 { 248 return resolveURIFeature( resource, type, alias ); 249 } 250 else if( feature.equals( Feature.SPEC ) ) 251 { 252 String path = resource.getResourcePath(); 253 String version =resource.getVersion(); 254 if( null == version ) 255 { 256 return path; 257 } 258 else 259 { 260 return path + "#" + version; 261 } 262 } 263 else if( feature.equals( Feature.PATH ) ) 264 { 265 if( null == type ) 266 { 267 final String error = 268 "Type must be supplied in conjuction with the uri feature."; 269 throw new FeatureRuntimeException( error ); 270 } 271 else 272 { 273 String id = type.getID(); 274 Artifact artifact = resource.getArtifact( id ); 275 try 276 { 277 File cached = 278 (File) artifact.toURL().getContent( new Class[]{File.class} ); 279 return cached.getCanonicalPath(); 280 } 281 catch( Exception e ) 282 { 283 final String error = 284 "Unable to resolve resource path."; 285 throw new FeatureRuntimeException( error, e ); 286 } 287 } 288 } 289 else if( feature.equals( Feature.FILENAME ) ) 290 { 291 if( null == type ) 292 { 293 final String error = 294 "Type must be supplied in conjuction with the filename feature."; 295 throw new IllegalArgumentException( error ); 296 } 297 String id = type.getID(); 298 return resource.getLayoutPath( id ); 299 } 300 else if( feature.equals( Feature.BASEDIR ) ) 301 { 302 File base = resource.getBaseDir(); 303 if( null == base ) 304 { 305 throw new IllegalArgumentException( "basedir" ); 306 } 307 else 308 { 309 try 310 { 311 return base.getCanonicalPath(); 312 } 313 catch( Exception e ) 314 { 315 final String error = 316 "Unexpected error while resolving project basedir [" + base + "]."; 317 throw new FeatureRuntimeException( error, e ); 318 } 319 } 320 } 321 else 322 { 323 final String error = 324 "Invalid feature [" + feature + "]."; 325 throw new FeatureRuntimeException( error ); 326 } 327 } 328 329 private static String resolveURIFeature( Resource resource, Type type ) 330 { 331 return resolveURIFeature( resource, type, false ); 332 } 333 334 private static String resolveURIFeature( Resource resource, Type type, boolean alias ) 335 { 336 if( null == type ) 337 { 338 final String error = 339 "Type must be supplied in conjuction with the uri feature request."; 340 throw new FeatureRuntimeException( error ); 341 } 342 else 343 { 344 String id = type.getID(); 345 if( alias ) 346 { 347 Version version = type.getVersion(); 348 if( null != version ) 349 { 350 Artifact artifact = resource.getArtifact( id ); 351 String group = artifact.getGroup(); 352 String name = artifact.getName(); 353 if( Version.NULL_VERSION.equals( version ) ) 354 { 355 return "link:" 356 + id 357 + ":" 358 + group 359 + "/" 360 + name; 361 } 362 else 363 { 364 int major = version.getMajor(); 365 int minor = version.getMinor(); 366 return "link:" 367 + id 368 + ":" 369 + group 370 + "/" 371 + name 372 + "#" 373 + major 374 + "." 375 + minor; 376 } 377 } 378 else 379 { 380 final String error = 381 "Cannot resolve link from resource [" 382 + resource 383 + "] because the resource does not declare production of an alias for the type [" 384 + id 385 + "]."; 386 throw new FeatureRuntimeException( error ); 387 } 388 } 389 else 390 { 391 Artifact artifact = resource.getArtifact( id ); 392 return artifact.toURI().toASCIIString(); 393 } 394 } 395 } 396 } 397